home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mint96sb.zoo / src / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-14  |  30.4 KB  |  1,207 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
  3. */
  4.  
  5. #include "mint.h"
  6. #include "version.h"
  7. #include "cookie.h"
  8. #include "xbra.h"
  9.  
  10. /* the kernel's stack size */
  11. #define STACK    8*1024L
  12.  
  13. /* if the user is holding down the magic shift key, we ask before booting */
  14. #define MAGIC_SHIFT 0x1        /* right shift */
  15.  
  16. /* magic number to show that we have captured the reset vector */
  17. #define RES_MAGIC 0x31415926L
  18.  
  19. static void xbra_install P_((xbra_vec *, long, void (*)()));
  20. static void init_intr P_((void));
  21. static void getmch P_((void));
  22. static void do_line P_((char *));
  23. static void shutmedown P_((PROC *));
  24. void shutdown P_((void));
  25. static void doset P_((char *,char *));
  26. static long ARGS_ON_STACK mint_criticerr P_((long));
  27.  
  28. static int gem_active;    /* 0 if AES has started, 1 otherwise */
  29.  
  30. static int  check_for_gem P_((void));
  31. static void run_auto_prgs P_((void));
  32.  
  33. #ifdef LATTICE
  34. /*
  35.  * AGK: this is witchcraft to completely replace the startup code for
  36.  * Lattice; doing so saves around 10K on the final binary and pulls only
  37.  * long division & multitplication from the library (and not even those
  38.  * if you compile for native '030). The drawback of this code is it
  39.  * passes no environment or command line whatsoever. Since I always
  40.  * set MiNT options & environment in 'mint.cnf' this is not a personal
  41.  * downer, however at some point in the future we ought to have a kernel
  42.  * parseargs() like call which sets these things up.
  43.  */ 
  44. BASEPAGE *_base;
  45.  
  46. static void
  47. start(BASEPAGE *bp)
  48. {
  49.     long shrinklen;
  50.     
  51.     _base = bp;
  52.     shrinklen = bp->p_tlen + bp->p_dlen + bp->p_blen + STACK + 0x100;
  53.     if (bp->p_lowtpa + shrinklen <= bp->p_hitpa) {
  54.         static char null[1] = {""};
  55.         static char *argv[2] = {null, NULL};
  56.         extern __builtin_putreg P_((int, long));    /* totally bogus */
  57.  
  58.         __builtin_putreg(15, bp->p_lowtpa + shrinklen);
  59.         Mshrink((void *)bp->p_lowtpa, shrinklen);
  60.         main(1, argv);
  61.     }
  62.     Pterm(ENSMEM);
  63. }
  64. #endif
  65.  
  66. #ifdef __GNUC__
  67. long _stksize = STACK;
  68. #ifndef PROFILING
  69. #include <minimal.h>
  70. #endif
  71. #endif
  72.  
  73. int curs_off = 0;    /* set if we should turn the cursor off when exiting */
  74. int mint_errno = 0;    /* error return from open and creat filesystem calls */
  75.  
  76. /*
  77.  * AGK: for proper co-processors we must consider saving their context.
  78.  * This variable when non-zero indicates that the BIOS considers a true
  79.  * coprocessor to be present. We use this variable in the context switch
  80.  * code to decide whether to attempt an FPU context save.
  81.  */
  82. short fpu = 0;
  83.  
  84. /*
  85.  * "mch" holds what kind of machine we are running on
  86.  */
  87. long mch = 0;
  88.  
  89. /*
  90.  * variable holds processor type
  91.  */
  92. long mcpu = 0;
  93.  
  94. /*
  95.  * variable set if someone has already installed an flk cookie
  96.  */
  97. int flk = 0;
  98.  
  99. /* program to run at startup */
  100. char orig_init[] = "init.prg";
  101. char *init_prg = orig_init;
  102. char init_tail[128];
  103.  
  104. /* initial environment for that program */
  105. char *init_env = 0;
  106. /* temporary pointer into that environment for setenv */
  107. char *env_ptr;
  108. /* length of the environment */
  109. long env_len;
  110.  
  111. /* GEMDOS pointer to current basepage */
  112. BASEPAGE **tosbp;
  113.  
  114. /* pointer to the BIOS keyboard shift variable */
  115. extern char *kbshft;    /* see bios.c */
  116.  
  117. /* version of TOS we're running over */
  118. int tosvers;
  119.  
  120. /* structures for keyboard/MIDI interrupt vectors */
  121. KBDVEC *syskey, oldkey;
  122. xbra_vec old_ikbd;            /* old ikbd vector */
  123.  
  124. /* values the user sees for the DOS, BIOS, and XBIOS vectors */
  125. long save_dos, save_bios, save_xbios;
  126.  
  127. /* values for original system vectors */
  128. xbra_vec old_dos, old_bios, old_xbios, old_timer, old_vbl, old_5ms;
  129. xbra_vec old_criticerr;
  130.  
  131. long old_term;
  132.  
  133. xbra_vec old_resvec;    /* old reset vector */
  134. long old_resval;    /* old reset validation */
  135.  
  136. #ifdef EXCEPTION_SIGS
  137. /* bus error, address error, illegal instruction, etc. vectors */
  138. xbra_vec old_bus, old_addr, old_ill, old_divzero, old_trace, old_priv;
  139. xbra_vec old_linef, old_chk, old_trapv, old_mmuconf, old_format, old_cpv;
  140. xbra_vec old_uninit, old_spurious, old_fpcp[7], old_pmmuill, old_pmmuacc;
  141. #endif
  142.  
  143. /* BIOS disk vectors */
  144. xbra_vec old_mediach, old_getbpb, old_rwabs;
  145.  
  146. /* BIOS drive map */
  147. long olddrvs;
  148.  
  149. extern Func bios_tab[], dos_tab[];
  150.  
  151. /* kernel info that is passed to loaded file systems and device drivers */
  152.  
  153. struct kerinfo kernelinfo = {
  154.     MAJ_VERSION, MIN_VERSION,
  155.     DEFAULT_MODE, 0,
  156.     bios_tab, dos_tab,
  157.     changedrv,
  158.     Trace, Debug, ALERT, FATAL,
  159.     kmalloc, kfree, umalloc, ufree,
  160.     strnicmp, stricmp, strlwr, strupr, ksprintf,
  161.     ms_time, unixtim, dostim,
  162.     nap, sleep, wake, wakeselect,
  163.     denyshare, denylock
  164. };
  165.  
  166. /* temporary stack for resets -- see intr.s */
  167. char tmpstack[256];
  168.  
  169. /* table of processor frame sizes in _words_ (not used on MC68000) */
  170. unsigned char framesizes[16] = {
  171. /*0*/    0,    /* MC68010/M68020/M68030/M68040 short */
  172. /*1*/    0,    /* M68020/M68030/M68040 throwaway */
  173. /*2*/    2,    /* M68020/M68030/M68040 instruction error */
  174. /*3*/    2,    /* M68040 floating point post instruction */
  175. /*4*/    3,    /* MC68LC040/MC68EC040 unimplemented floating point instruction */
  176. /*5*/    0,    /* NOTUSED */
  177. /*6*/    0,    /* NOTUSED */
  178. /*7*/    26,    /* M68040 access error */    
  179. /*8*/    25,    /* MC68010 long */    
  180. /*9*/    6,    /* M68020/M68030 mid instruction */
  181. /*A*/    12,    /* M68020/M68030 short bus cycle */
  182. /*B*/    42,    /* M68020/M68030 long bus cycle */
  183. /*C*/    0,    /* CPU32 bus error - don't know how big this one is :-( */
  184. /*D*/    0,    /* NOTUSED */
  185. /*E*/    0,    /* NOTUSED */
  186. /*F*/    0    /* NOTUSED */
  187. };
  188.  
  189. /* TOS and MiNT cookie jars, respectively. See the comments and code 
  190.  * after main() for further details
  191.  */
  192.  
  193. COOKIE *oldcookie, *newcookie;
  194.  
  195. /*
  196.  * install a new vector for address "addr", using the XBRA protocol.
  197.  * must run in supervisor mode!
  198.  */
  199.  
  200. static void
  201. xbra_install(xv, addr, func)
  202.     xbra_vec *xv;
  203.     long addr;
  204.     void (*func)();
  205. {
  206.     xv->xbra_magic = XBRA_MAGIC;
  207.     xv->xbra_id = MINT_MAGIC;
  208.     xv->jump = JMP_OPCODE;
  209.     xv->this = func;
  210.     xv->next = *((struct xbra **)addr);
  211.     *((short **)addr) = &xv->jump;
  212. }
  213.  
  214. /*
  215.  * MiNT critical error handler; all it does is to jump through
  216.  * the vector for the current process
  217.  */
  218.  
  219. static long ARGS_ON_STACK
  220. mint_criticerr(error)
  221.     long error;    /* high word is error, low is drive */
  222. {
  223.     return (*curproc->criticerr)(error);
  224. }
  225.  
  226. /* initialize all interrupt vectors and new trap routines
  227.  * we also get here any TOS variables that we're going to change
  228.  * (e.g. the pointer to the cookie jar) so that rest_intr can
  229.  * restore them.
  230.  */
  231.  
  232. static void
  233. init_intr()
  234. {
  235.     extern void mint_bios(), mint_dos(), mint_timer(), mint_vbl();
  236.     extern void mint_5ms();        /* AKP */
  237.     extern void mint_xbios(), reset();
  238.     extern void new_ikbd();
  239.       extern void new_bus(), new_addr(), new_ill(), new_divzero(),
  240.         new_trace(), new_priv(), new_linef(), new_chk(), new_trapv(),
  241.         new_fpcp(), new_mmu(), new_format(), new_cpv(), new_uninit(),
  242.         new_spurious(), new_pmmuacc();
  243.     short savesr;
  244.     int i;
  245.  
  246.     syskey = (KBDVEC *)Kbdvbase();
  247.     oldkey = *syskey;
  248.  
  249.     xbra_install(&old_ikbd, (long)(&syskey->ikbdsys), new_ikbd);
  250.  
  251. /* gratuitous (void *) for Lattice */
  252.     old_term = (long)Setexc(0x102, (void *)-1UL);
  253.  
  254.     savesr = spl7();
  255.  
  256.     xbra_install(&old_dos, 0x84L, mint_dos);
  257.     save_dos = (long)old_dos.next;
  258.  
  259.     xbra_install(&old_bios, 0xb4L, mint_bios);
  260.     save_bios = (long)old_bios.next;
  261.  
  262.     xbra_install(&old_xbios, 0xb8L, mint_xbios);
  263.     save_xbios = (long)old_xbios.next;
  264.  
  265.     xbra_install(&old_timer, 0x400L, mint_timer);
  266.     xbra_install(&old_criticerr, 0x404L, (void (*)())mint_criticerr);
  267.     xbra_install(&old_5ms, 0x114L, mint_5ms);
  268.     xbra_install(&old_vbl, 4*0x1cL, mint_vbl);
  269.     xbra_install(&old_resvec, 0x42aL, reset);
  270.     old_resval = *((long *)0x426L);
  271.     *((long *)0x426L) = RES_MAGIC;
  272.  
  273.     spl(savesr);
  274.  
  275. #ifdef EXCEPTION_SIGS
  276. /* set up signal handlers */
  277.     xbra_install(&old_bus, 8L, new_bus);
  278.     xbra_install(&old_addr, 12L, new_addr);
  279.     xbra_install(&old_ill, 16L, new_ill);
  280.     xbra_install(&old_divzero, 20L, new_divzero);
  281.     xbra_install(&old_trace, 36L, new_trace);
  282.     xbra_install(&old_priv, 32L, new_priv);
  283.     if (tosvers >= 0x106)
  284.         xbra_install(&old_linef, 44L, new_linef);
  285.     xbra_install(&old_chk, 24L, new_chk);
  286.     xbra_install(&old_trapv, 28L, new_trapv);
  287.     for (i = (int)(sizeof(old_fpcp) / sizeof(old_fpcp[0])); i--; ) {
  288.         xbra_install(&old_fpcp[i], 192L + i * 4, new_fpcp);
  289.     }
  290.     xbra_install(&old_mmuconf, 224L, new_mmu);
  291.     xbra_install(&old_pmmuill, 228L, new_mmu);
  292.     xbra_install(&old_pmmuacc, 232L, new_pmmuacc);
  293.     xbra_install(&old_format, 56L, new_format);
  294.     xbra_install(&old_cpv, 52L, new_cpv);
  295.     xbra_install(&old_uninit, 60L, new_uninit);
  296.     xbra_install(&old_spurious, 96L, new_spurious);
  297. #endif
  298.  
  299. /* set up disk vectors */
  300.     xbra_install(&old_mediach, 0x47eL, (void (*)())new_mediach);
  301.     xbra_install(&old_rwabs, 0x476L, (void (*)())new_rwabs);
  302.     xbra_install(&old_getbpb, 0x472L, (void (*)())new_getbpb);
  303.     olddrvs = *((long *)0x4c2L);
  304.  
  305. /* set up cookie jar */
  306.     oldcookie = *CJAR;    /* CJAR defined in cookie.h */
  307.     install_cookies();
  308. }
  309.  
  310. /* restore all interrupt vectors and trap routines */
  311. /*
  312.  * NOTE: This is *not* the approved way of unlinking XBRA trap handlers.
  313.  * Normally, one should trace through the XBRA chain. However, this is
  314.  * a very unusual situation: when MiNT exits, any TSRs or programs running
  315.  * under MiNT will no longer exist, and so any vectors that they have
  316.  * caught will be pointing to never-never land! So we do something that
  317.  * would normally be considered rude, and restore the vectors to
  318.  * what they were before we ran.
  319.  * BUG: we should restore *all* vectors, not just the ones that MiNT caught.
  320.  */
  321.  
  322. void
  323. restr_intr()
  324. {
  325.     short savesr;
  326.     int i;
  327.  
  328.     savesr = spl7();
  329.     *syskey = oldkey;        /* restore keyboard vectors */
  330.     *tosbp = _base;            /* restore GEMDOS basepage pointer */
  331.     *CJAR = oldcookie;        /* restore old cookie jar */
  332.  
  333. #ifdef EXCEPTION_SIGS
  334.     *((long *)0x08L) = (long) old_bus.next;
  335.     *((long *)0x0cL) = (long) old_addr.next;
  336.     *((long *)0x10L) = (long) old_ill.next;
  337.     *((long *)0x14L) = (long) old_divzero.next;
  338.     *((long *)0x20L) = (long) old_priv.next;
  339.     *((long *)0x24L) = (long) old_trace.next;
  340.     if (old_linef.next)
  341.         *((long *)0x2cL) = (long) old_linef.next;
  342.     *((long *)0x18L) = (long) old_chk.next;
  343.     *((long *)0x1cL) = (long) old_trapv.next;
  344.     for (i = (int)(sizeof(old_fpcp) / sizeof(old_fpcp[0])); i--; ) {
  345.         ((long *)0xc0L)[i] = (long) old_fpcp[i].next;
  346.     }
  347.     *((long *)0xe0L) = (long) old_mmuconf.next;
  348.     *((long *)0xe4L) = (long) old_pmmuill.next;
  349.     *((long *)0xe8L) = (long) old_pmmuacc.next;
  350.     *((long *)0x38L) = (long) old_format.next;
  351.     *((long *)0x34L) = (long) old_cpv.next;
  352.     *((long *)0x3cL) = (long) old_uninit.next;
  353.     *((long *)0x60L) = (long) old_spurious.next;
  354. #endif
  355.     *((long *)0x84L) = (long) old_dos.next;
  356.     *((long *)0xb4L) = (long) old_bios.next;
  357.     *((long *)0xb8L) = (long) old_xbios.next;
  358.     *((long *)0x408L) = old_term;
  359.     *((long *)0x404L) = (long) old_criticerr.next;
  360.     *((long *)0x114L) = (long) old_5ms.next;
  361.     *((long *)0x400L) = (long) old_timer.next;
  362.     *((long *)0x70L) = (long) old_vbl.next;
  363.     *((long *)0x426L) = old_resval;
  364.     *((long *)0x42aL) = (long) old_resvec.next;
  365.     *((long *)0x476L) = (long) old_rwabs.next;
  366.     *((long *)0x47eL) = (long) old_mediach.next;
  367.     *((long *)0x472L) = (long) old_getbpb.next;
  368.     *((long *)0x4c2L) = olddrvs;
  369.  
  370.     spl(savesr);
  371. }
  372.  
  373.  
  374. /* we save the TOS supervisor stack pointer so that we can reset it when
  375.    calling Pterm() (not that anyone will ever want to leave MiNT :-)).
  376.  */
  377.  
  378. long tosssp;        /* TOS supervisor stack pointer */
  379.  
  380.  
  381. /*
  382.  * enter_kernel: called every time we enter the MiNT kernel via a trap
  383.  * call. Sets up the GEMDOS and BIOS vectors to point to TOS, and
  384.  * sets up other vectors and system variables appropriately. Note that
  385.  * calling enter_kernel multiple times is probably NOT a good idea,
  386.  * but the code will allow it.
  387.  */
  388.  
  389. short in_kernel = 0;
  390.  
  391. void ARGS_ON_STACK
  392. enter_kernel()
  393. {
  394.     short save_sr;
  395.  
  396.     if (in_kernel) return;
  397.  
  398.     save_sr = spl7();
  399.     save_dos = *((long *) 0x84L);
  400.     save_bios = *((long *) 0xb4L);
  401.     save_xbios = *((long *) 0xb8L);
  402.     *((long *) 0x84L) = (long)old_dos.next;
  403.     *((long *) 0xb4L) = (long)old_bios.next;
  404.     *((long *) 0xb8L) = (long)old_xbios.next;
  405.     *tosbp = _base;
  406.  
  407.     in_kernel = 1;
  408.     spl(save_sr);
  409. }
  410.  
  411. /*
  412.  * leave_kernel: called before leaving the kernel, either back to
  413.  * user mode or when calling a signal handler or the GEMDOS
  414.  * terminate vector. Note that interrupts should be disabled before
  415.  * this routine is called.
  416.  */
  417.  
  418. void ARGS_ON_STACK
  419. leave_kernel()
  420. {
  421.     *((long *) 0x84L) = save_dos;
  422.     *((long *) 0xb4L) = save_bios;
  423.     *((long *) 0xb8L) = save_xbios;
  424.     *tosbp = curproc->base;
  425.     in_kernel = 0;
  426. }
  427.  
  428. /*
  429.  * shut down processes; this involves waking them all up, and sending
  430.  * them SIGTERM to give them a chance to clean up after themselves
  431.  */
  432.  
  433. static void
  434. shutmedown(p)
  435.     PROC *p;
  436. {
  437.     UNUSED(p);
  438.     curproc->wait_cond = 0;
  439. }
  440.  
  441. void
  442. shutdown()
  443. {
  444.     PROC *p;
  445.     int proc_left = 0;
  446.  
  447.     curproc->sighandle[SIGCHLD] = SIG_IGN;
  448.  
  449.     for (p = proclist; p; p = p->gl_next) {
  450.         if (p->pid == 0) continue;
  451.         if (p->wait_q != ZOMBIE_Q && p->wait_q != TSR_Q) {
  452.             if (p->wait_q != READY_Q) {
  453.                 rm_q(p->wait_q, p);
  454.                 add_q(READY_Q, p);
  455.             }
  456.             post_sig(p, SIGTERM);
  457.             proc_left++;
  458.         }
  459.     }
  460.  
  461.     if (proc_left) {
  462.         /* sleep a little while, to give the other processes a chance to
  463.            shut down
  464.          */
  465.  
  466.         addtimeout(1000, shutmedown);
  467.         do {
  468.             sleep(WAIT_Q, (long)shutdown);
  469.         } while (curproc->wait_cond == (long)shutdown);
  470.     }
  471. }
  472.  
  473. #ifdef __GNUC__
  474. int
  475. main(argc, argv, envp)
  476.     int argc;
  477.     char **argv, **envp;
  478. #else
  479. int
  480. main(argc, argv)
  481.     int argc;
  482.     char **argv;
  483. #endif
  484. {
  485.     long *sysbase;
  486.     long r;
  487.     extern int debug_level;        /* in debug.c */
  488.     static char buf[SPRINTF_MAX];
  489.     static char curpath[128];
  490.     long yn;
  491.     FILEPTR *f;
  492.  
  493. /* Allow the user to abort the boot if the magic combination of shift keys
  494.  * is held down (see MAGIC_SHIFT above)
  495.  */
  496.     if ((Kbshift(-1) & MAGIC_SHIFT) == MAGIC_SHIFT) {
  497.         Cconws("Boot MiNT? (y/n) ");
  498.         yn = Cconin() & 0x7f;
  499.         if (yn != 'y' && yn != 'Y') {
  500.             Cconws("\r\n\r\nMiNT not booted, at user's request.\r\n");
  501.             Pterm0();
  502.         }
  503.     }
  504.  
  505.     if (argv[0][0] == 0) {    /* maybe started from the desktop */
  506.         curs_off = 1;
  507.     }
  508.  
  509.     if (argc > 1) {
  510.         debug_level++;
  511.     }
  512.     if (argc > 2) {
  513.         debug_level++;
  514.     }
  515.  
  516. /* greetings */
  517. #ifdef EZMINT
  518.     Cconws("\r\n\033eMiNT is Not TOS: EasyMiNT version ");
  519. #else
  520.     Cconws("\r\n\033eMiNT is Not TOS: MiNT version ");
  521. #endif
  522.  
  523. #ifdef PATCHLEVEL
  524.     ksprintf(buf, VERS_STRING, MAJ_VERSION, MIN_VERSION, PATCHLEVEL);
  525. #else
  526.     ksprintf(buf, VERS_STRING, MAJ_VERSION, MIN_VERSION);
  527. #endif
  528.     Cconws(buf);
  529.     Cconws("\r\nCopyright 1990,1991,1992 Eric R. Smith\r\n");
  530.  
  531. #ifdef __TURBOC__
  532.     Cconws("PRELIMINARY PureC compiled version!\r\n");
  533. #endif
  534.  
  535.     Cconws("Use this program at your own risk!\r\n");
  536.     Cconws("See the file \"copying\" for distribution conditions\r\n");
  537.  
  538.     gem_active = check_for_gem();    /* this must be done from user mode */
  539.  
  540. /*
  541.  * get the current directory, so that we can switch back to it after
  542.  * the file systems are properly initialized
  543.  */
  544. /* set the current directory for the current process */
  545.     (void)Dgetpath(curpath, 0);
  546.  
  547.     tosssp = (long)Super(0L);    /* enter supervisor mode */
  548.  
  549. /* figure out what kind of machine we're running on */
  550. /* biosfs wants to know this, so we have to do it very
  551.  * early in our initialization
  552.  */
  553.     getmch();
  554.  
  555. /* get GEMDOS pointer to current basepage */
  556. /* 0x4f2 points to the base of the OS; here we can find the OS compilation
  557.    date, and (in newer versions of TOS) where the current basepage pointer
  558.    is kept; in older versions of TOS, it's at 0x602c
  559.  */
  560.     sysbase = *((long **)(0x4f2L));    /* gets the RAM OS header */
  561.     sysbase = (long *)sysbase[2];    /* gets the ROM one */
  562.  
  563.     tosvers = (int)(sysbase[0] & 0x0000ffff);
  564.     if (tosvers == 0x100) {
  565.         if ((sysbase[7] & 0xfffe0000L) == 0x00080000L)
  566.             tosbp = (BASEPAGE **)0x873cL;    /* SPANISH ROM */
  567.         else
  568.             tosbp = (BASEPAGE **) 0x602cL;
  569.         kbshft = (char *) 0x0e1bL;
  570.     } else {
  571.         tosbp = (BASEPAGE **) sysbase[10];
  572.         kbshft = (char *) sysbase[9];
  573.     }
  574.  
  575. /* The TT TOS release notes are wrong... this is the real way to test
  576.  * for Bconmap ability
  577.  */
  578.     has_bconmap = (Bconmap(0) == 0);
  579.  
  580. /* initialize memory */
  581.     init_mem();
  582.  
  583. /* initialize the basic file systems */
  584.     init_filesys();
  585.  
  586. /* initialize processes */
  587.     init_proc();
  588.  
  589. /* initialize system calls */
  590.     init_dos();
  591.     init_bios();
  592.     init_xbios();
  593.  
  594. /* NOTE: there's a call to kmalloc embedded in install_cookies, which
  595.  * is called by init_intr; so make sure this is the last of the
  596.  * init_* things called!
  597.  */
  598.     init_intr();
  599.     enter_kernel();
  600.  
  601.     if (!gem_active) {
  602. /* make MiNT invisible in the basepage chain, so that
  603.  * programs that rely on a certain basepage chain
  604.  * structure to determine whether or not they were run
  605.  * from the desktop will have a better chance of working.
  606.  * NOTE THAT THIS IS ONLY DONE TO HELP OUT BRAIN-DAMAGED
  607.  * SOFTWARE: do *not* try counting basepages to figure
  608.  * out whether or not you were run from the desktop!!!
  609.  */
  610.         rootproc->base = _base->p_parent;
  611.     }
  612.  
  613. /* set up standard file handles for the current process
  614.  * do this here, *after* init_intr has set the Rwabs vector,
  615.  * so that AHDI doesn't get upset by references to drive U:
  616.  */
  617.     f = do_open("U:\\DEV\\CONSOLE", O_RDWR, 0, (XATTR *)0);
  618.     if (!f) {
  619.         FATAL("unable to open CONSOLE device");
  620.     }
  621.     curproc->control = f;
  622.     curproc->handle[0] = f;
  623.     curproc->handle[1] = f;
  624.     f->links = 3;
  625.  
  626.     f = do_open("U:\\DEV\\MODEM1", O_RDWR, 0, (XATTR *)0);
  627.     curproc->aux = f;
  628.     if (has_bconmap) {
  629.     /* If someone has already done a Bconmap call, then
  630.      * MODEM1 may no longer be the default
  631.      */
  632.         bconmap(curbconmap);
  633.         f = curproc->aux;    /* bconmap can change curproc->aux */
  634.     }
  635.     if (f) {
  636.         curproc->handle[2] = f;
  637.         f->links++;
  638.     }
  639.     f = do_open("U:\\DEV\\CENTR", O_RDWR, 0, (XATTR *)0);
  640.     if (f) {
  641.         curproc->handle[3] = curproc->prn = f;
  642.         f->links = 2;
  643.     }
  644.     if (f) {
  645.         f = do_open("U:\\DEV\\MIDI", O_RDWR, 0, (XATTR *)0);
  646.         curproc->midiin = curproc->midiout = f;
  647.         f->links = 2;
  648.     }
  649.  
  650. /* load external file systems */
  651.     if (*curpath) {
  652.         (void)d_setpath(curpath);
  653.     }
  654.     
  655. #ifndef PROFILING
  656. /* load_filesys causes media changes :-( */
  657.     load_filesys();
  658. #endif
  659.  
  660. /* note that load_filesys changed the
  661.  * directory on us!!
  662.  */
  663.     if (*curpath) {
  664.         (void)d_setpath(curpath);
  665.     }
  666.     
  667. /* load the configuration file */
  668.     load_config();
  669.  
  670.  
  671.     *((long *)0x4c2L) |= PSEUDODRVS;
  672.  
  673.     if (init_env == 0)
  674.         init_env = (char *)_base->p_env;
  675.  
  676. /* empty environment? Set the PATH variable to the root of the current drive */
  677.     if (init_env[0] == 0) {
  678.         static char path_env[] = "PATH=\0C:\0";
  679.         path_env[6] = curproc->curdrv + 'A';
  680.         init_env = path_env;
  681.     }
  682.  
  683. /* run any programs appearing after us in the AUTO folder */
  684.     run_auto_prgs();
  685.  
  686. /* run the initial program */
  687.  
  688.     r = p_exec(0, init_prg, init_tail, init_env);
  689.  
  690. /* if it isn't found, and the user didn't say otherwise, try GEM */
  691.     if (r == EFILNF && init_prg == orig_init) {
  692.         if (!gem_active) {
  693.             BASEPAGE *bp; int pid;
  694.             bp = (BASEPAGE *)p_exec(7, (char *)7L, (char *)"\0", init_env);
  695.             bp->p_tbase = *((long *) 0x4feL );
  696.             pid = (int)p_exec(106, (char *)"GEM", bp, 0L);
  697.             if (pid > 0) {
  698.             do {
  699.                 r = p_wait3(0, (long *)0);
  700.             } while(pid != ((r & 0xffff0000L) >> 16));
  701.             r &= 0x0000ffff;
  702.             }
  703.         } else {
  704. Cconws("If MiNT is run after GEM starts, you must specify a program\r\n");
  705. Cconws("to run initially in MINT.CNF, with an INIT= line\r\n");
  706.             r = 0;
  707.         }
  708.     }
  709.  
  710.     if (r < 0) {
  711.         ksprintf(buf, "FATAL: couldn't run %s\r\n", init_prg);
  712.         Cconws(buf);
  713.     }
  714.  
  715.     if (r) {
  716.         ksprintf(buf, "exit code: %ld\r\n", r);
  717.         Cconws(buf);
  718.     }
  719.  
  720.     rootproc->base = _base;
  721.  
  722. /* shut down all processes gracefully */
  723.     shutdown();
  724.  
  725. /* put everything back and exit */
  726.     restr_intr();
  727.     close_filesys();
  728.  
  729.     (void)Super((void *)tosssp);    /* gratuitous (void *) for Lattice */
  730.     Cconws("leaving MiNT\r\n");
  731.  
  732.     if (curs_off)
  733.         Cconws("\033f");    /* disable cursor */
  734.  
  735.     return 0;
  736. }
  737.  
  738.  
  739. /*
  740.  * cookie jar handling routines. The "cookie jar" is an area of memory
  741.  * reserved by TOS for TSR's and utility programs; the idea is that
  742.  * you put a cookie in the jar to notify people of available services.
  743.  * The BIOS uses the cookie jar in TOS 1.6 and higher; for earlier versions
  744.  * of TOS, the jar is always empty (unless someone added a cookie before
  745.  * us; POOLFIX does, for example).
  746.  * MiNT establishes an entirely new cookie jar (with the old cookies copied
  747.  * over) and frees it on exit. That's because TSR's run under MiNT
  748.  * will no longer be accessible after MiNT exits.
  749.  * MiNT also puts a cookie in the jar, with tag field 'MiNT' (of course)
  750.  * and with the major version of MiNT in the high byte of the low word,
  751.  * and the minor version in the low byte.
  752.  */
  753.  
  754. void
  755. install_cookies()
  756. {
  757.     COOKIE *cookie;
  758.     int i, ncookies;
  759.  
  760.     /* note that init_intr sets oldcookie to the old cookie jar */
  761.  
  762.     ncookies = 0;
  763.     cookie = oldcookie;
  764.     if (cookie) {
  765.         while (cookie->tag.aslong != 0) {
  766.         /* check for true FPU co-processor */
  767.             if (!strncmp(cookie->tag.aschar, "_FPU",4) &&
  768.                  (cookie->value >> 16) >= 2)
  769.                 fpu = 1;
  770.         /* check for _FLK cookie */
  771.             else if (!strncmp(cookie->tag.aschar, "_FLK",4))
  772.                 flk = 1;
  773.             cookie++; ncookies++;
  774.         }
  775.     }
  776.  
  777. /* NOTE: obviously, we can do this only if init_intr is called
  778.  * _after_ memory, processes, etc. have been initialized
  779.  */
  780.     newcookie = (COOKIE *)kmalloc((ncookies + 16)*sizeof(COOKIE));
  781.     assert(newcookie);
  782.  
  783. /* copy the old cookies to the new jar */
  784.  
  785.     for (i = 0; i < ncookies; i++) {
  786.         newcookie[i] = oldcookie[i];
  787.     }
  788.  
  789. /* install MiNT cookie */
  790.     strncpy(newcookie[i].tag.aschar, "MiNT", 4);
  791.     newcookie[i].value = (MAJ_VERSION << 8) | MIN_VERSION;
  792.     i++;
  793.  
  794. /* install _FLK cookie to indicate that file locking works */
  795.     if (!flk) {
  796.         strncpy(newcookie[i].tag.aschar, "_FLK", 4);
  797.         newcookie[i].value = 0;
  798.         i++;
  799.     }
  800.  
  801. /* the last cookie should have a 0 tag, and a value indicating the number
  802.  * of slots, total
  803.  */
  804.  
  805.     newcookie[i].tag.aslong = 0;
  806.     newcookie[i].value = ncookies+16;
  807.  
  808.     *CJAR = newcookie;
  809.  
  810. }
  811.  
  812. /*
  813.  * get the value of the _MCH cookie, if one exists
  814.  * this must be done in a separate routine because the machine type
  815.  * is needed when initializing the bios file system, whereas
  816.  * install_cookies is not called until everything is installed
  817.  * In fact, getmch() should be called before *anything* else is
  818.  * initialized, so that if we find a MiNT cookie already in the
  819.  * jar we can bail out early.
  820.  */
  821.  
  822. static void
  823. getmch()
  824. {
  825.     COOKIE *jar;
  826.  
  827.     jar = *CJAR;    /* CJAR defined in cookie.h */
  828.     if (jar) {
  829.         while (jar->tag.aslong != 0) {
  830.         /* check for machine type */
  831.             if (!strncmp(jar->tag.aschar, "_MCH",4)) {
  832.                 mch = jar->value;
  833.             } else if (!strncmp(jar->tag.aschar, "_CPU", 4)) {
  834.                 mcpu = jar->value;
  835.             } else if (!strncmp(jar->tag.aschar, "MiNT",4)) {
  836.                 Cconws("MiNT is already installed!!\r\n");
  837.                 (void)Super((void *)tosssp);
  838.                 Pterm(2);
  839.             }
  840.             jar++;
  841.         }
  842.     }
  843. }
  844.  
  845. /*
  846.  * routines for reading the configuration file
  847.  * we allow the following commands in the file:
  848.  * # anything        -- comment
  849.  * INIT=file        -- specify boot program
  850.  * cd dir        -- change directory/drive
  851.  * ren file1 file2    -- rename a file
  852.  * sln file1 file2    -- create a symbolic link
  853.  * echo message        -- print a message on the screen
  854.  * setenv var value    -- set an environment variable
  855.  *
  856.  * BUG: if you use setenv in mint.cnf, *none* of the original environment
  857.  * gets passed to children. This is rarely a problem if mint.prg is
  858.  * in the auto folder.
  859.  */
  860.  
  861. extern short bconbdev, bconbsiz;    /* from bios.c */
  862.  
  863. static void
  864. doset(name, val)
  865.     char *name, *val;
  866. {
  867.     char *t;
  868.  
  869.     if (!strcmp(name, "INIT")) {
  870.         t = kmalloc(strlen(val)+1);
  871.         if (!t) return;
  872.         strcpy(t, val);
  873.         init_prg = t;
  874.         while (*t && !isspace(*t)) t++;
  875. /* get the command tail, too */
  876.         if (*t) {
  877.             *t++ = 0;
  878.             strncpy(init_tail+1, t, 125);
  879.             init_tail[0] = strlen(init_tail+1);
  880.         }
  881.         return;
  882.     }
  883.     if (!strcmp(name, "CON")) {
  884.         FILEPTR *f;
  885.         int i;
  886.  
  887.         f = do_open(val, O_RDWR, 0, (XATTR *)0);
  888.         if (f) {
  889.             for (i = -1; i < 2; i++) {
  890.                 do_close(curproc->handle[i]);
  891.                 curproc->handle[i] = f;
  892.                 f->links++;
  893.             }
  894.             f->links--;    /* correct for overdoing it */
  895.         }
  896.         return;
  897.     }
  898.     if (!strcmp(name, "PRN")) {
  899.         FILEPTR *f;
  900.  
  901.         f = do_open(val, O_RDWR|O_CREAT|O_TRUNC, 0, (XATTR *)0);
  902.         if (f) {
  903.             do_close(curproc->handle[2]);
  904.             do_close(curproc->prn);
  905.             curproc->prn = curproc->handle[2] = f;
  906.             f->links = 2;
  907.         }
  908.         return;
  909.     }
  910.     if (!strcmp(name, "BIOSBUF")) {
  911.         if (*val == 'n' || *val == 'N') {
  912.             if (bconbsiz) bflush();
  913.             bconbdev = -1;
  914.         }
  915.         return;
  916.     }
  917.     if (!strcmp(name, "DEBUG_LEVEL")) {
  918.         extern int debug_level;
  919.         if (*val >= '0' && *val <= '9')
  920.             debug_level = (int)atol(val);
  921.         else ALERT("Bad arg to \"DEBUG_LEVEL\" in cnf file");
  922.         return;
  923.     }
  924.     if (!strcmp(name, "DEBUG_DEVNO")) {
  925.         extern int out_device;
  926.         if (*val >= '0' && *val <= '9')
  927.             out_device= (int)atol(val);
  928.         else ALERT("Bad arg to \"DEBUG_DEVNO\" in cnf file");
  929.         return;
  930.     }
  931.  
  932. #ifdef FASTTEXT
  933.     if (!strcmp(name, "HARDSCROLL")) {
  934.         int i;
  935.         extern int hardscroll;
  936.  
  937.         if (!strcmp(val, "AUTO")) {
  938.             hardscroll = -1;
  939.             return;
  940.         }
  941.         i = *val++;
  942.         if (i < '0' || i > '9') return;
  943.         hardscroll = i-'0';
  944.         i = *val;
  945.         if (i < '0' || i > '9') return;
  946.         hardscroll = 10*hardscroll + i - '0';
  947.         return;
  948.     }
  949. #endif
  950.     if (!strcmp(name, "MAXMEM")) {
  951.         long r;
  952.  
  953.         r = atol(val) * 1024L;
  954.         if (r > 0)
  955.             p_setlimit(1, r);
  956.     }
  957.     if (!strcmp(name, "PSEUDODRIVES")) {
  958.         ALERT("PSEUDODRIVES= no longer supported");
  959.         return;
  960.     }
  961.     ALERT("Unknown variable `%s'", name);
  962. }
  963.  
  964. /* Execute a line from the config file */
  965. static void
  966. do_line(line)
  967.     char *line;
  968. {
  969.     char *cmd, *arg1, *arg2;
  970.     char *newenv;
  971.     char *t;
  972.     int i;
  973.  
  974.     while (*line == ' ') line++;
  975.     if (*line == '#') return;    /* ignore comments */
  976.     if (!*line) return;        /* and also blank lines */
  977.  
  978.     cmd = line;
  979. /* check for variable assignments (e.g. INIT=, etc.) */
  980. /*
  981.  * AGK: note we check for spaces whilst scanning so that an environment
  982.  * variable may include an =, this has the unfortunate side effect that
  983.  * the '=' _has_ to be concatenated to the variable name (INIT etc.)
  984.  */
  985.     for (t = cmd; *t && *t != ' '; t++) {
  986.         if (*t == '=') {
  987.             *t++ = 0;
  988.             doset(cmd, t);
  989.             return;
  990.         }
  991.     }
  992.  
  993. /* OK, assume a regular command; break it up into 'cmd', 'arg1', arg2' */
  994.  
  995.     while (*line && *line != ' ') line++;
  996.     if (*line == ' ') {
  997.         *line++ = 0;
  998.         while (*line == ' ') line++;
  999.     }
  1000.  
  1001.     if (!strcmp(cmd, "echo")) {
  1002.         c_conws(line); c_conws("\r\n");
  1003.         return;
  1004.     }
  1005.     arg1 = line;
  1006.     while (*line && *line != ' ') line++;
  1007.     if (*line) {
  1008.         *line++ = 0;
  1009.         while (*line == ' ') line++;
  1010.     }
  1011.     if (!strcmp(cmd, "cd")) {
  1012.         int drv;
  1013.         (void)d_setpath(arg1);
  1014.         drv = toupper(*arg1) - 'A';
  1015.         if (arg1[1] == ':') (void)d_setdrv(drv);
  1016.         return;
  1017.     }
  1018.     if (!strcmp(cmd, "exec")) {
  1019.         static char cmdline[128];
  1020.         int i;
  1021.  
  1022.         i = strlen(line);
  1023.         if (i > 126) i = 126;
  1024.         cmdline[0] = i;
  1025.         strncpy(cmdline+1, line, i);
  1026.         cmdline[i+1] = 0;
  1027.         i = (int)p_exec(0, arg1, cmdline, init_env);
  1028.         if (i == -33) {
  1029.             ALERT("%s: file not found", arg1);
  1030.         } else if (i < 0) {
  1031.             ALERT("%s: error while attempting to execute", arg1);
  1032.         }
  1033.         return;
  1034.     }
  1035.     if (!strcmp(cmd, "setenv")) {
  1036.         if (strlen(arg1) + strlen(line) + 4 + (env_ptr - init_env) >
  1037.                              env_len) {
  1038.             long j;
  1039.  
  1040.             env_len += 1024;
  1041.             newenv = umalloc(env_len);
  1042.             if (init_env) {
  1043.                 t = init_env;
  1044.                 j = env_ptr - init_env;
  1045.                 env_ptr = newenv;
  1046.                 for (i = 0; i < j; i++)
  1047.                     *env_ptr++ = *t++;
  1048.                 if (init_env)
  1049.                     ufree(init_env);
  1050.             } else {
  1051.                 env_ptr = newenv;
  1052.             }
  1053.             init_env = newenv;
  1054.         }
  1055.         while (*arg1) {
  1056.             *env_ptr++ = *arg1++;
  1057.         }
  1058.         *env_ptr++ = '=';
  1059.         while (*line) {
  1060.             *env_ptr++ = *line++;
  1061.         }
  1062.         *env_ptr++ = 0;
  1063.         *env_ptr = 0;
  1064.         return;
  1065.     }
  1066.  
  1067.     arg2 = line;
  1068.     while (*line && *line != ' ') line++;
  1069.     if (*line) {
  1070.         *line = 0;
  1071.     }
  1072.     if (!strcmp(cmd, "alias")) {
  1073.         int drv;
  1074.         long r;
  1075.         fcookie root_dir;
  1076.         extern int aliasdrv[];
  1077.  
  1078.         drv = toupper(*arg1) - 'A';
  1079.         if (drv < 0 || drv >= NUM_DRIVES) {
  1080.             ALERT("Bad drive (%c:) in alias", drv+'A');
  1081.             return;
  1082.         }
  1083.         r = path2cookie(arg2, NULL, &root_dir);
  1084.         if (r) {
  1085.             ALERT("alias: TOS error %ld while looking for %s",
  1086.                 r, arg2);
  1087.             return;
  1088.         }
  1089.         aliasdrv[drv] = root_dir.dev + 1;
  1090.         *((long *)0x4c2L) |= (1L << drv);
  1091.         curproc->root[drv] = curproc->curdir[drv] = root_dir;
  1092.         return;
  1093.     }
  1094.     if (!strcmp(cmd, "sln")) {
  1095.         (void)f_symlink(arg1, arg2);
  1096.         return;
  1097.     }
  1098.     if (!strcmp(cmd, "ren")) {
  1099.         (void)f_rename(0, arg1, arg2);
  1100.         return;
  1101.     }
  1102.     ALERT("syntax error in mint.cnf");
  1103. }
  1104.  
  1105. #define BUF 512
  1106. #define LINE 256
  1107.  
  1108. void
  1109. load_config()
  1110. {
  1111.     int fd;
  1112.     long r;
  1113.     char buf[BUF+1], c;
  1114.     char line[LINE+1];
  1115.     char *from;
  1116.     int count = 0;
  1117.  
  1118.     TRACE(("reading configuration file"));
  1119.     fd = (int) f_open("mint.cnf", 0);
  1120.     if (fd < 0)
  1121.         fd = (int) f_open("\\mint\\mint.cnf", 0);
  1122.     if (fd < 0) return;
  1123.     buf[BUF] = 0;
  1124.     from = &buf[BUF];
  1125.     line[LINE] = 0;
  1126.  
  1127.     for(;;) {
  1128.         c = *from++;
  1129.         if (!c) {
  1130.             r = f_read(fd, (long)BUF, buf);
  1131.             if (r <= 0) break;
  1132.             buf[r] = 0;
  1133.             from = buf;
  1134.         } else if (c == '\r') {
  1135.             continue;
  1136.         } else if (c == '\n') {
  1137.             line[count] = 0;
  1138.             do_line(line);
  1139.             count = 0;
  1140.         } else {
  1141.             if (count < LINE) {
  1142.                 line[count++] = c;
  1143.             }
  1144.         }
  1145.     }
  1146.     f_close(fd);
  1147. }
  1148.  
  1149. /*
  1150.  * run programs in the AUTO folder that appear after MINT.PRG
  1151.  * some things to watch out for:
  1152.  * (1) make sure GEM isn't active
  1153.  * (2) make sure there really is a MINT.PRG in the auto folder
  1154.  */
  1155.  
  1156. /*
  1157.  * some global variables used to see if GEM is active
  1158.  */
  1159. static short aes_intout[64];
  1160. static short aes_dummy[64];
  1161. static short aes_globl[15];
  1162. static short aes_cntrl[6] = { 10, 0, 1, 0, 0 };
  1163.  
  1164. short *aes_pb[6] = { aes_cntrl, aes_globl, aes_dummy, aes_intout,
  1165.              aes_dummy, aes_dummy };
  1166.  
  1167. /* check for whether GEM is active; remember, this *must* be done in
  1168.  * user mode
  1169.  */
  1170.  
  1171. static int
  1172. check_for_gem()
  1173. {
  1174.     call_aes(aes_pb);    /* does an appl_init */
  1175.     return aes_globl[0];
  1176. }
  1177.  
  1178. static void
  1179. run_auto_prgs()
  1180. {
  1181.     DTABUF *dta;
  1182.     long r;
  1183.     static char pathspec[32] = "\\AUTO\\";
  1184.     short runthem = 0;    /* set to 1 after we find MINT.PRG */
  1185.  
  1186. /* if the AES is running, don't check AUTO */
  1187.  
  1188.     if (gem_active) {
  1189.         return;
  1190.     }
  1191.  
  1192. /* OK, now let's run through \\AUTO looking for
  1193.  * programs...
  1194.  */
  1195.     dta = (DTABUF *)f_getdta();
  1196.     r = f_sfirst("\\AUTO\\*.PRG", 0);
  1197.     while (r >= 0) {
  1198.         if (!strcmp(dta->dta_name, "MINT.PRG"))
  1199.             runthem = 1;
  1200.         else if (runthem) {
  1201.             strcpy(pathspec+6, dta->dta_name);
  1202.             (void)p_exec(0, pathspec, (char *)"", init_env);
  1203.         }
  1204.         r = f_snext();
  1205.     }
  1206. }
  1207.